#include "DrawTool.h"
#include "Common/FileSys.h"
#include "Utility.h"
#include "TouchPanel.h"

#if defined WIN_PC
	#include "Win32/Video.h"
#elif defined WIN_CE
	#include "WinCE/Video.h"
#elif defined _BF533
	#include "BF533/Video.h"
#elif defined _DAVINCI
	#include "DAVINCI/Video.h"
#endif

/////////////////////////////////////////////////////////////////////////////

TCanvas	_VideoFrame;	// this is private and system depended, 
						// plz don't use it!
TCanvas	_Offscreen;

TText	_Text16;
	TText	_Text18;
	TText	_Text33;

int		RGB_WHITE;
int		RGB_BLACK;
int		RGB_RED;
int		RGB_GREEN;
int		RGB_BLUE;
int		RGB_YELLOW;
int		RGB_MAGENTA;
int 	RGB_GRAY;

static TImageList*	_pImageList = NULL;

static void	dt_SettingDefaultColor();

static void dt_Report(char *str);

/////////////////////////////////////////////////////////////////////////////

BOOL dt_Initialize()
{
	// Init the hardware video device
	if (dev_VideoInit() == 0)
		return FALSE;

	ASSERT_DEBUG(Frame_pBits);

	LOG("---- dump graphic info ----\n");
	LOG("Video frame: %d x %d x %d bytes\n", Frame_width, Frame_height, Frame_stride / Frame_width);
	LOG("Application: %d x %d\n", SCREEN_WIDTH, SCREEN_HEIGHT);
#if defined __RGB16 
	LOG("Using 16-bits mode %s\n", (__DOUBLE_SCREEN__) ? "+ double screen" : "");
#elif defined __RGB24 
	LOG("Using 24-bits mode %s\n", (__DOUBLE_SCREEN__) ? "+ double screen" : "");
#endif
	LOG("---------------------------\n");

	// Make a canvas  mapping the video device
	g_DefineCanvas(&_VideoFrame, Frame_pBits, Frame_width, Frame_height, Frame_stride);


	// Make a off-screen canvas
	g_CreateCanvas(&_Offscreen, SCREEN_WIDTH, SCREEN_HEIGHT);

	// Clear all first
	g_FillRectNC( &_Offscreen, 0, 0, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1, RGB_BLACK );


	g_CreateText(&_Text16,  "/ming16", 1);
	g_CreateText(&_Text18,  "/font18", 1);//hangsheng add 20071207
	g_CreateText(&_Text33,  "/font33", 1);

//	Trace memory here!

	dt_SettingDefaultColor();

	// set a debug reporter
	d_set_report_callback( dt_Report );	

    return TRUE;
}

void dt_SettingDefaultColor()
{
	RGB_WHITE	= _RGB( 255, 255, 255 );
	RGB_BLACK	= _RGB( 0, 0, 0 );
	RGB_RED		= _RGB( 255, 0, 0 );
	RGB_GREEN	= _RGB( 0, 255, 0 );
	RGB_BLUE	= _RGB( 0, 0, 255 );
	RGB_YELLOW	= _RGB( 255, 255, 0 );
	RGB_MAGENTA	= _RGB( 255, 0, 255 );
	RGB_GRAY	= _RGB( 220, 220, 220 );
}

void dt_Report(char *str)
{	
	int i = 0, x = 0, y = 30, ch;

	if( str == NULL )
		return;

	g_SetTextFormat( FONT12, TEXT_OPAQUE, RGB_WHITE, RGB_RED, 0 );

	while( ( ch = str[i] ) )
	{
		if( ch == ',' )
		{
			x = 0;
			y += 12;
			i++;
			while( ( ch = str[i] ) == ' ' )
				i++;
		}

		g_PutcXY( OFFSCREEN, FONT12, x, y, ch );
		x += 6;
		i++;
	}

	dt_Present();
	
	os_Sleep( 10000 );
}
void	dt_Present_part(TRect rect)//hangsheng 20080131 add
{
	#ifdef _BF533
		g_CopyCanvas_YUV_BF533_part(&_VideoFrame, &_Offscreen,rect);
	#endif

	dev_VideoPresent();
}


void dt_Present() 
{
#if defined _WIN32
	#if __DOUBLE_SCREEN__
		g_DblCanvas( &_VideoFrame, &_Offscreen );
	#else
		g_CopyCanvas( &_VideoFrame, &_Offscreen );
	#endif
#elif defined _BF533
	g_CopyCanvas(&_VideoFrame, &_Offscreen );//g_CopyCanvas_YUV_BF533(&_VideoFrame, &_Offscreen ); //BF54X_UPGRADE
#endif

	dev_VideoPresent();
}

TImage*	dt_GetImagePtr(int no)
{
	return g_GetImageFromList( _pImageList, no );
}

static int _iAntiAlaised = 1;

void dt_EnableAntiAlaised(int enable)
{
	_iAntiAlaised = enable;
}

//#define _BEVEL_FONT
/* English version */
BOOL dt_PutsPathEng(const TCanvas *canvas, const TText *text, TPoint* points, int count, const char *str)
{
	static TPoint path[256];
	int cw = 6;	// character width
//	int ch = 6;	// character height
	int i;
	int x, y;
	int t, b, l, r, x_start, y_start;
	int len;
	int hline;
	unsigned char *s;
	int tries = 0;

	TText *rotText;
	int rotDir;
	int w, h;

	ASSERT_DEBUG(count % 2 == 0);

tryagain_en:
	// Get the bounding rectangle of these points	
	l = x_start = points[0].x;
	t = y_start	= points[0].y;
	r = points[0].x;
	b = points[0].y;

	for (i = 1; i < count; i++)
	{
		x = points[i].x;
		y = points[i].y;

		if (x < l)  	{ l = x; y_start = y; }
		else if (x > r) { r = x; }
		if (y < t)      { t = y; x_start = x; }
		else if (y > b) { b = y; }
	}

	w = r - l;	// bounding width
	h = b - t;	// bounding height

	if (w > 2 * h)		// when slop > 2
	{
		rotText = FONT13;
		rotDir = 0;
		hline = 1;
	}
//	else if (w * 2 > h)	// when slop > 0.5
	else if (w * 3 > h)	// when slop > 0.33
//	else if (w * 4 > h)	// when slop > 0.25
	{
#ifdef _BEVEL_FONT
		rotText = FONT13N;
		if (y_start < (b + t) / 2)
		{
			rotDir = 0;
		}
		else
		{
			rotDir = -1;
		}
#else
		rotText = FONT13;
		rotDir = 0;
#endif
		hline = 1;
	}
	else
	{	
		rotText = FONT13;
		rotDir = 1;
		hline = 0;
	}
	
	r -= l;	// r is bounding width
	b -= t;	// b is bounding height

	len = strlen(str) * cw;
//	len = strlen(str) * cw / 2;

	// Adjust the order of points(l->r, t->b) and determine path direction
	if (hline == 1) // r * 2 > b * 3)
	{
		// Horizontal run:
		if (len > r)
			return FALSE;	// not enough space for whole text

		if (tries)
			len = 14;				// align in left
		else
			len = (r - len) / 2;	// align in center
//			len = 0;				// align in left
				
		x = l + len;
		y = y_start;

		for (i = 0; i < count; i += 2)
		{
			if (points[i].x > points[i+1].x)
			{		
				SWAP(points[i].x, points[i+1].x);
				SWAP(points[i].y, points[i+1].y);
			}
//debug only -OB
//			g_DrawLine(canvas, points[i].x, points[i].y, points[i+1].x, points[i+1].y, _RGB(0,0,255));
		}
	}
	else
	{
		// Vertical run:
		if (len > b)
			return FALSE;	// not enough space for whole text

		if (tries)
			len = 14;				// align in top
		else
			len = (b - len) / 2;	// align in center
//			len = 0;				// align in top

		x = x_start;
		y = t + len;

		for (i = 0; i < count; i += 2)
		{
			if (points[i].y > points[i+1].y)
			{		
				SWAP(points[i].x, points[i+1].x);
				SWAP(points[i].y, points[i+1].y);
			}
//debug only -OB
//			g_DrawLine(canvas, points[i].x, points[i].y, points[i+1].x, points[i+1].y, _RGB(255,0,0));
		}
	}

//debug only -OB
/*	for (i = 0; i < count; i+=2)
	{
		g_DrawLine(canvas, points[i].x, points[i].y, points[i+1].x, points[i+1].y, _RGB(0,0,0));
	}
	for (i = 0; i < count; i++)
	{
		g_DrawLine(canvas, points[i].x-3, points[i].y-3, points[i].x+3, points[i].y+3, _RGB(0,0,0));
		g_DrawLine(canvas, points[i].x+3, points[i].y-3, points[i].x-3, points[i].y+3, _RGB(0,0,0));
	}
*/
    s = (unsigned char *) str;

	l = t = r = b = -1;

	len = 0;

	path[0].x = -1;

    while (*s)
    {
		if (hline)
		{
			if (x >= l && x < r )
			{
				y = ((x-l) * (b-t)) / (r-l) + t;
			}
			else
				l = -1;	// re-trigger segment search
		}
		else
		{
			if (y >= t && y < b)
			{				
				x = ((y-t) * (r-l)) / (b-t) + l;
			}
			else
				l = -1;	// re-trigger segment search
		}				

		// new segment searching...
		if (l == - 1)
		{
			for (i = 0; i < count; i += 2)
			{
				if (tries == 0 && r != -1 && (points[i].x != r || points[i].y != b))
				{
					continue;	// not a continued segment
				}
				if (points[i].x == points[i+1].x && points[i].y == points[i+1].y)
					continue;	// not a valid segment

				if (hline)
				{
					if (x >= points[i].x && x < points[i+1].x)
					{
						break;
					}
				}
				else
				{
					if (y >= points[i].y && y < points[i+1].y)
					{
						break;
					}
				}
				
				if (tries == 0 && r != -1 && i < count - 1)
				{
					// continued segment found not but the x,y not fall in
					// use tail point search next continued
					r = points[i+1].x;
					b = points[i+1].y;
					i = -2;
				}
			}

			if (i >= count)
			{
//debug only -OB
//				if(tries == 0)
//				g_DrawRect(canvas, r-5, b-5, r+5, b+5, _RGB(0,255,0));
//			else
//				g_DrawRect(canvas, r-5, b-5, r+5, b+5, _RGB(0,0,255));

				if( strlen((char *)s) < 3)
					break;	// damn..just remain 2 chars can't fill in path, so we force use extrapolation

				if( tries == 0 )
				{
					tries = 1;
					goto tryagain_en;
				}
				return FALSE;
			}

			l = points[i].x;
			t = points[i].y;
			r = points[i+1].x;
			b = points[i+1].y;

//debug only -OB
//			g_DrawRect(canvas, points[i].x-3, points[i].y-3, points[i].x+3, points[i].y+3, _RGB(255,0,0));

			continue;
		}

		path[len].x = x;
		path[len].y = y;
		len++;

		if (rotDir)
		{
			cw = g_GetFontWidth( &(rotText->ASCII), *s - 0x20) + 1;
		}
		else
		{
			cw = g_GetFontWidth( &(rotText->ASCII), *s - 0x20);
		}
		s++;

#ifdef _BEVEL_FONT
		if (rotText == FONT13N)
			cw = (cw * 2 ) / 3 + 1;
#endif
		if (hline)
			x += cw;
		else
			y += cw;
	} 

	path[len].x = -1;

	s = (unsigned char *) str;
	i = 0;
	while (path[i].x != -1)
	{
//		if (ut_IsBig5Code(s))
//		{
//			g_PutcXY(canvas, text, path[i].x, path[i].y, *s, *(s + 1));
//			s += 2;
//		}
//		else
		{
			if (rotDir)
//				cw = g_DrawFontR(canvas, &(rotText->ASCII), path[i].x, path[i].y, *s - 0x20, rotDir) + 1;
				cw = g_DrawAsciiFontR(canvas, &(rotText->ASCII), path[i].x, path[i].y, *s - 0x20, rotDir) + 1;
			else
				cw = g_PutcXY(canvas, rotText, path[i].x, path[i].y, *s);
			s++;
		}

		i++;
	}

	if (*s == 0)
		return TRUE;

	// else the path too short, do extrapolation for remains
	x = r = path[i-1].x;
	y = b = path[i-1].y;

	do 
	{	// find a base point (not nearly)
		l = path[i-2].x;
		t = path[i-2].y;
		i--;
	} while(i > 1 && abs(r - l) < 2 && abs(b - t) < 2);

	if (i < 2)
		return FALSE;	// although draw some but not completed because too short path!

	while (*s)
	{
		if (hline)
		{
			x += cw;
			y = (b - t) * (x - l) / (r - l) + t;
		}
		else
		{
			y += cw;
			x = (y - t) * (r - l) / (b - t) + l;
		}

		if (rotDir)
//			cw = g_DrawFontR(canvas, &(rotText->ASCII), x, y, *s - 0x20, rotDir) + 1;
			cw = g_DrawAsciiFontR(canvas, &(rotText->ASCII), x, y, *s - 0x20, rotDir) + 1;
		else
			cw = g_PutcXY(canvas, rotText, x, y, *s);
		s++;
	}

	return TRUE;
}

void dt_DrawImageTransSmall(TCanvas* canvas, int x, int y, TImage* image, int keyColor)
{
	int cx, cy;
	int idx, i, j;
	int c;
	
	cx = (image->width * 3) / 4;
	cy = (image->height * 3) / 4;

	for( j = 0; j < cy; j++ )
	{
		for( i = 0; i < cx; i++ )
		{
			idx = (((j * 4) / 3) * image->width + (i * 4) / 3) * PIXEL_SIZE;

			c = READ_PIXEL_PTR( (UInt8*)image->data + idx );

			if ( c != keyColor )
				g_DrawPixel( canvas, x + i, y + j, c);
		}
	}
}

void dt_DrawImageTransSmall21(TCanvas* canvas, int x, int y, TImage* image, int keyColor)
{
	int cx, cy;
	int idx, i, j;
	int c;
	
	cx = image->width >> 1;
	cy = image->height >> 1;

	for( j = 0; j < cy; j++ )
	{
		for( i = 0; i < cx; i++ )
		{
			idx = ((j << 1) * image->width + (i << 1)) * PIXEL_SIZE;

			c = READ_PIXEL_PTR( (UInt8*)image->data + idx );

			if ( c != keyColor )
				g_DrawPixel( canvas, x + i, y + j, c);
		}
	}
}

void dt_DrawLineThick(TCanvas *canvas, int x1, int y1, int x2, int y2, int color, int thick)
{
	int dx, dy;
    int row;
    int d, incr1, incr2;

   if (g_LineClipping(canvas, &x1, &y1, &x2, &y2) == 0)
		return;

    if (x1 > x2)
    {
        SWAP(x1, x2);
        SWAP(y1, y2);
    }

    row = (y2 > y1) ? 1 : (-1);

    dx = x2 - x1;
    dy = ABS_SUB(y2, y1);
	
    // Draw a filled vertical line only
    if (!dx)
    {
        x1 -= (thick >> 1);
        x2 = x1 + thick -1;

        if (y1 > y2)
           SWAP(y1, y2);

		g_FillRect(canvas, x1, y1, x2, y2, color);

        return;
    }

    // Draw a filled horizontal line only
    if (!dy)
    {
        y1 -= (thick >> 1);
        y2 = y1 + thick -1;

        if (x1 > x2)
           SWAP(x1, x2);

		g_FillRect(canvas, x1, y1, x2, y2, color);

        return;
    }

    // Draw sloping line only...
	x1 -= thick / 2;
	y1 -= thick / 2;

    // If more-or-less horizontal
    if (dx >= dy)
    {
        g_FillRect(canvas, x1, y1, x1 + thick - 1, y1 + thick -1, color);
        x1++;

        d     = (dy << 1) - dx;
        incr1 = (dy - dx) << 1;
        incr2 = dy << 1;

        while (dx--)
        {
            if (d > 0)
            {
                y1 += row;
                d += incr1;
            }
            else
                d += incr2;
			
            g_FillRect(canvas, x1, y1, x1 + thick - 1, y1 + thick -1, color);
            x1++;      
        }
    }
    else // more-or-less vertical
    {
        g_FillRect(canvas, x1, y1, x1 + thick - 1, y1 + thick -1, color);
        y1 += row;         

        d     = (dx << 1) - dy;
        incr1 = (dx - dy) << 1;
        incr2 = dx << 1;

        while (dy--)
        {
            if (d > 0)
            {
                x1++;
                d += incr1;
            }
            else
                d += incr2;

		    g_FillRect(canvas, x1, y1, x1 + thick - 1, y1 + thick -1, color);
			y1 += row; 
        }
    }   
}

static TRect	_screen_clip = { 0, 0, SCREEN_WIDTH-1, SCREEN_HEIGHT-1 };
static int		_screen_clip_width = -1;
static int		_Screen_clip_height = -1;
void dt_SetScreenClip( TRect rect, BOOL bWrite )
{ 
#ifndef WIN_CE
	if( !SAME_RECT( rect, _screen_clip ) )
	{
		_screen_clip = rect;
		_screen_clip_width = -1;
		_Screen_clip_height = -1;
	}

	if( bWrite )
	{
/*		char szValue[MAX_FIELDNAME_LEN];
		TCfgObj* pCfg = ncg_GetCfgObj( CFG_SYS );
		_screen_clip = rect;

		sprintf( szValue, "%02d", _screen_clip.left );
		pCfg->SetStrValueByName( pCfg, "ScreenLeft", 0, szValue );
		sprintf( szValue, "%02d", _screen_clip.top );
		pCfg->SetStrValueByName( pCfg, "ScreenTop", 0, szValue );
		sprintf( szValue, "%02d", _screen_clip.right );
		pCfg->SetStrValueByName( pCfg, "ScreenRight", 0, szValue );
		sprintf( szValue, "%02d", _screen_clip.bottom );
		pCfg->SetStrValueByName( pCfg, "ScreenBottom", 0, szValue );

		ncg_WriteCfg( pCfg );*/

	}
#endif
}

TRect dt_GetScreenClip()
{
	return _screen_clip;
}

int	dt_GetScreenClipWidth()
{
	if( _screen_clip_width == -1 )
		_screen_clip_width = RECT_WIDTH(_screen_clip);
	return _screen_clip_width;
}

int	dt_GetScreenClipHeight()
{
	if( _Screen_clip_height == -1 )
		_Screen_clip_height = RECT_HEIGHT(_screen_clip);
	return _Screen_clip_height;
}

BOOL dt_ClipTouchGetXY( int *x, int *y)
{
	TPosCoor pos;
	
	*x = -1; *y = -1;
	dev_TouchPanelGetXY(&pos.x,&pos.y);
#if __DOUBLE_SCREEN__
	pos.x /= 2;
	pos.y /= 2;
#endif
	if( ut_PtInRect( pos, _screen_clip ) )
	{
		*x = pos.x - dt_GetScreenClip().left;
		*y = pos.y - dt_GetScreenClip().top;
		return TRUE;
	}
	return FALSE;
}
